var TAG_SPRITE_MANAGER = 1;
var PTM_RATIO = 32;             //valor de relación para la conversión de pixeles a metros

//MARGENES para establecer los límites de la mesa
MARGEN_SUPERIOR = 90,           //Margen entre el límite superior y el borde (box2d) de la mesa
MARGEN_INFERIOR = 90,           //idem inferior
MARGEN_DERECHO = 30,            //idem derecho
MARGEN_IZQUIERDO = 20,          //idem izquierdo
DIAMETRO = 50,                  //diámetro del sprite de la ficha y de la ficha misma
RADIO = DIAMETRO / 2;           //radio del sprite....
WIDTH = 1200;
HEIGHT = 450;

FACTORFUERZA = 32;

var FPS = 60;                   //FPS deseados

MesaLayer = cc.Layer.extend({

    //Variables "globales" a la Mesa
    world:null,                     //variable para el mundo físico
    cont:0,
    fichaColocada:null,             //indica si el jugador colocó la ficha en la mesa. o sea si hizo click o no
    fichaLista:null,                //indica si la ficha ya fue colocada en la mesa,
    fichaDisparada:null,            //indica si la ficha ya fue disparada, que se le aplicó una fuerza.
    turno:null,                     //almacena a que numero de jugador le corresponde el tiro actual
    disparador:null,                //variable para el "disparador" de la ficha
    jugadores:null,                 //estructura para almacenar hasta cuatro jugadores
    screenSize:null,
    miWebSocket:null,
    miTurno:1,
    meToca:false,
    miNombre:null,
    numJugadores:null,              //numero de jugadores, falta actualizar el hardcode de 4
    yaTire:false,
    ultimoTiro:false,
    jugando:false,

    ctor:function () {  //constructor de la Mesa
        this.setTouchEnabled(true);
		this.miWebSocket = new cacona();
        this.miWebSocket.setMesa(this);
        //this.wsEnviarNombreJugador("pedro");
        //setAccelerometerEnabled( true );

        //abreviaciones para los tipos de box2d
        var b2Vec2 = Box2D.Common.Math.b2Vec2
            , b2BodyDef = Box2D.Dynamics.b2BodyDef
            , b2Body = Box2D.Dynamics.b2Body
            , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            , b2World = Box2D.Dynamics.b2World
            , b2DebugDraw = Box2D.Dynamics.b2DebugDraw
            , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;

        this.screenSize = cc.Director.getInstance().getWinSize();    //obtengo el tamaño de la pantalla, o sea el canvas

        //Definiendo el mundo
        var doSleep = false;                            //un objeto que duerme no necesita simulacion.
        var gravedad = new b2Vec2(0, 0);                //sin gravedad
        this.world = new b2World(gravedad, doSleep);    //creo el mundo sin gravedad, y permito objetos "durmientes"
        this.world.SetContinuousPhysics(true);

        var pared = new Jugador();
        pared.setNombre("PARED");

        var pisoFixtureDef = new b2FixtureDef;
        pisoFixtureDef.density = 1;
        pisoFixtureDef.friction = 0,5;
        pisoFixtureDef.restitution = 1;

        var pisoBodyDef = new b2BodyDef;
        pisoBodyDef.type = b2Body.b2_staticBody;    //static es que no se mueve
        pisoFixtureDef.shape = new b2PolygonShape;
        pisoBodyDef.userData = pared;

        //limite inferior
        pisoFixtureDef.shape.SetAsBox(this.screenSize.width, 0);       //El Largo de la caja es todo el ancho de la "pantalla"
        pisoBodyDef.position.Set(0, MARGEN_INFERIOR / PTM_RATIO);     //el limite inferior empieza en la esquina inferior izquierda
        this.world.CreateBody(pisoBodyDef).CreateFixture(pisoFixtureDef);

        //limite superior
        pisoBodyDef.position.Set(0, (this.screenSize.height - MARGEN_SUPERIOR )/ PTM_RATIO);
        pisoFixtureDef.shape.SetAsBox(this.screenSize.width, 0);       //El Largo de la caja es todo el ancho de la "pantalla"
        this.world.CreateBody(pisoBodyDef).CreateFixture(pisoFixtureDef);



        // limite derecho
        pisoBodyDef.position.Set((this.screenSize.width-MARGEN_DERECHO)/PTM_RATIO, this.screenSize.height / PTM_RATIO);
        pisoFixtureDef.shape.SetAsBox(0, this.screenSize.height / PTM_RATIO);       //El alto de la caja es todo el alto de la "pantalla"
        this.world.CreateBody(pisoBodyDef).CreateFixture(pisoFixtureDef);
        // limite izquierdo
        pisoBodyDef.position.Set(MARGEN_IZQUIERDO/PTM_RATIO, this.screenSize.height / PTM_RATIO);
        pisoFixtureDef.shape.SetAsBox(0, this.screenSize.height / PTM_RATIO);       //El alto de la caja es todo el alto de la "pantalla"
        this.world.CreateBody(pisoBodyDef).CreateFixture(pisoFixtureDef);


        this.disparador = new NodoDisparador();                                   //disparador es la "onda" de la ficha
        this.disparador.setPosition(cc.p(0, 0));
        this.addChild(this.disparador);
        this.disparador.schedule(this.disparador.myUpdate, 1 / FPS);    //refrescamos el disparador a los mismos FPS que lo demas

        //creamos el administrador de los sprites. Agregaremos los sprites a este administrador y el se encarga de agregarlos al mundo
        var mgr = cc.SpriteBatchNode.create(s_pathBlock, 4);    //4 = capacidad
        this.addChild(mgr, 0, TAG_SPRITE_MANAGER);              //agregamos el administrador de sprites a la mesa

        this.jugadores = new Jugadores();           //creo la variable jugadores
        this.jugadores.inicializar(4);
        this.dibujarPuntajes();                     //aca xq se tiene que ejecutar una sola vez

        var clistener = new ColisionListener();
        this.world.SetContactListener(clistener);
        this.scheduleUpdate();
    },
    setTurno:function(num){
        this.turno = num;
        if (num==1){
            this.ultimoTiro=true;
        }else{
            this.ultimoTiro = false;
        }
    },
    setNumJugadores:function(val){
        this.numJugadores = val;
    },
    inicializar:function(){
        this.jugando = true;
        this.turno=1;                               //El máximo de turnos es 4
        this.yaTire=false;
        this.ultimoTiro = false;
        this.fichaColocada = false;                 //indica si el jugador colocó la ficha en la mesa. o sea si hizo click o no
        this.fichaLista = false;                    //indica si la ficha ya fue colocada en la mesa,
        this.fichaDisparada = false;                //indica si la ficha ya fue disparada, que se le aplicó una fuerza.

        this.cont = 0;


        var batch = this.getChildByTag(TAG_SPRITE_MANAGER); //llamo al administrador de sprites

        for (var i=1;i<=4;i++){                         //cargo una imagen distinta para cada jugador de un spriteList de 2x2
            var x = (i > 2 ? 1 : 0);
            var y = i % 2;
            this.jugadores.getJugador(i).setImagen(cc.Sprite.createWithTexture(batch.getTexture(),cc.rect(x* DIAMETRO, y*DIAMETRO, DIAMETRO, DIAMETRO)));
        }
    },

    dibujarPuntajes:function(){
        //Esta funcion se ejecuta una sola vez.
            for (i=1;i<=4;i++){
                var l = this.jugadores.getJugador(i).getLabel();
                this.addChild(l);
                l.scheduleUpdate();
                //cc.log(l.getString());
            }
    },
    realizarTiro:function(numJugador,fx,fy){        //aplica la fuerza a la ficha colocada por el jugador correspondiente
        /** numJugador esta al dope. hay que sacarlo
         */
        var j = this.jugadores.getJugador(this.turno);
        var b = j.getFicha();
        var force = new Box2D.Common.Math.b2Vec2((fx/PTM_RATIO)*FACTORFUERZA,(fy/PTM_RATIO)*FACTORFUERZA);    //ya que es una sola no uso las abreviaciones
        var point = b.GetWorldCenter();
        b.ApplyImpulse(force,point);              //Aplico la fuerza a la ficha
        if (this.turno == this.miTurno){
            this.yaTire = true;
            cc.log("yaTire=true");
        }

    },
    setUltimoYaTiro:function(){
        this.ultimoTiro = true;
    },
    draw:function()    {//función de dibujador para la mesa

    },
    agregarFicha:function (xx,yy) {
        /**
         *  Función que agrega un objeto con forma circular al mundo físico,
         *  con su correspondiente sprite asociado,
         *  el sprite lo sacamos del jugador
         */
        var batch = this.getChildByTag(TAG_SPRITE_MANAGER); //obtengo el Administrador de sprites

        var x = (this.turno > 2 ? 1 : 0);                   //igual que arriba, estas dos lineas son para
        var y = this.turno % 2;                             //seleccionar una imagen de un spritelist de 2x2

        var sprite = this.jugadores.getJugador(this.turno).getImagen();

        var mil = cc.p(xx, yy);
        cc.log("x = " + mil.x + " mil.y = " + mil.y);
        sprite.setPosition(mil);

        var b2BodyDef = Box2D.Dynamics.b2BodyDef
            , b2Body = Box2D.Dynamics.b2Body
            , b2Vec2 = Box2D.Common.Math.b2Vec2
            , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
            , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;

        var bodyDef = new b2BodyDef();
        var j = this.jugadores.getJugador(this.turno);
        bodyDef.type = b2Body.b2_dynamicBody;
        bodyDef.position.Set(xx / PTM_RATIO, yy / PTM_RATIO);
        bodyDef.userData = j;
        var body = this.world.CreateBody(bodyDef);
        //guardamos el cuerpo del jugador en turno

        j.setFicha(body);


        var radio = RADIO / PTM_RATIO;
        var dynamicBox = new b2CircleShape(radio);

        var fixtureDef = new b2FixtureDef();
        fixtureDef.shape = dynamicBox;
        fixtureDef.density = 1;
        fixtureDef.friction = 0.3;
        b2FixtureDef.restitution = 0.5;
        body.CreateFixture(fixtureDef);
        body.SetLinearDamping(2);       //desaceleracion
        body.ResetMassData();       //Es necesario ????????
        //body.scheduleUpdate();
    },
    update:function (dt) {
        /**
         *  Función de actualización de la mesa
         *  nos brindará hasta FPS frames por segundo
         */


        var velocityIterations = 6;
        var positionIterations = 16;

        this.world.Step(dt, velocityIterations, positionIterations);
        //cc.log(dt);
        if (this.jugando) {
                //Iteramos sobre los objetos en el mundo físico
                for (var b = this.world.GetBodyList(); b; b = b.GetNext()) {
                    if (b.GetUserData() != null && b.GetUserData().getNombre() != "PARED") {
                        //Sincronizar la posición del sprite con el body correspondiente
                        var myActor = b.GetUserData().getImagen();
                        myActor.setPosition(cc.p(b.GetPosition().x * PTM_RATIO, b.GetPosition().y * PTM_RATIO));
                        myActor.setRotation(-1 * cc.RADIANS_TO_DEGREES(b.GetAngle()));
                        var xx = b.GetAngularVelocity();
                        b.SetAngularDamping(1);
                        //b.SetAngularVelocity();
                    }
                }
                if (this.cont == 10) {
                    //cc.log("cont=30");
                    var sig = this.sigTurno();
                    //cc.log("turno:" + this.turno + " this.sigTurno:" + sig);

                    if ((this.yaTire ) && (this.turno == sig)){    //si fui el que tiro
                        //cc.log("miTurno:" + this.miTurno + "  this.turno:" + this.turno);
                        if (this.jugadores.getJugador(this.miTurno).getQuieto()){   //y si mi ficha esta quieta
                            this.wsEnviarFichaQuieta();
                            this.yaTire = false;
                        }else{
                            //this.wsEnviarSincroPosFicha();  //si no quedo quieta mando las posiciones
                        }
                    }else
                    if (this.turno == 4 && this.yaTire){
                        if (this.jugadores.getJugador(this.miTurno).getQuieto()){   //y si mi ficha esta quieta
                            this.wsEnviarFichaQuieta();
                            this.yaTire = false;
                        }
                    }

                    this.cont = 0;
                }else{
                    this.cont++;
                }
        }

    },

    sigTurno:function(){
        if (this.miTurno == 4)
            return 4;
        var sig = parseInt(this.miTurno) + 1;
        return sig;
    },
    actualizarPuntajes:function(){

        for (i=1;i<=4;i++){
            var j = this.jugadores.getJugador(i);
            var x = j.getFicha().GetPosition().x;
            var y = j.getFicha().GetPosition().y;
            var x1 = (this.screenSize.width/PTM_RATIO)- 158 / PTM_RATIO;
            var x2 = (this.screenSize.width/PTM_RATIO)- 244 / PTM_RATIO;
            var x3 = (this.screenSize.width/PTM_RATIO)- 334 / PTM_RATIO;
            if (x > x1){
                j.setPuntaje(j.getPuntaje() + 10);
            }
            if (x > x2){
                j.setPuntaje(j.getPuntaje() + 10);
            }
            if (x > x3){
                j.setPuntaje(j.getPuntaje() + 10);
            }
            //cc.log("pos: " + j.getXAnt());
            //cc.log("x1: " + x1 + "x2: " + x2 + "x3: " + x3);
            //cc.log("jugador" + i + ": " + j.getPuntaje());
        }
        this.borrarFichas();
        this.inicializar();
    },
    borrarFichas:function(){
        /**
         *  Borra las fichas, tanto el elemento físico como el sprite
         */
        for (i=1;i<=4;i++){
            var j = this.jugadores.getJugador(i);
            var batch = this.getChildByTag(TAG_SPRITE_MANAGER);
            batch.removeChild(j.getImagen());       //borro el sprite
            this.world.DestroyBody(j.getFicha());   //borro el objeto de box2d
        }
    },

    onTouchesBegan:function (touches, event) {
        cc.log("turno=" + this.turno + " miTurno=" + this.miTurno + "meToca=" + this.meToca);
        if (this.meToca=="true"){
            for (var it = 0; it < touches.length; it++) {
                var touch = touches[it];
                var location = touch.getLocation();

                if (!this.fichaColocada && !this.fichaLista && !this.fichaDisparada){   //vamos a mostrar una imagen dejando q la arrastre
                    //Si aun no fue colocada
                    this.wsEnviarMostrarFicha();
                }else{
                    if (this.fichaColocada && this.fichaLista && !this.fichaDisparada){
                        this.wsEnviarMostrarDisparador(location.x,location.y);
                    }
                }
            }
        }
    },
    onTouchesMoved:function (touches, event) {
        if (this.meToca=="true"){
            if (this.fichaColocada && !this.fichaLista && !this.fichaDisparada){        // actualizo posicion Imagen
                for (var it = 0; it < touches.length; it++) {
                    var touch = touches[it];
                    var location = touch.getLocation();
                    this.wsEnviarActualizacionPosicionFicha(location.x,location.y);
                }
            }else{                                                                       // actualizo posicion Disparador
                if (this.fichaColocada && this.fichaLista && !this.fichaDisparada){
                    for (var it = 0; it < touches.length; it++) {
                        var touch = touches[it];
                        var location = touch.getLocation();
                        this.wsEnviarActualizacionPosicionDisparador(location.x,location.y);
                    }
                }
            }
        }
    },
    onTouchesEnded:function (touches, event) {
        if (this.meToca=="true"){
            for (var it = 0; it < touches.length; it++) {
                var touch = touches[it];
                if (!touch)
                    break;
                var location = touch.getLocation();
                if (this.fichaColocada && !this.fichaLista && !this.fichaDisparada){
                    this.wsEnviarColocada(location.x,location.y);
                }else{
                    if (this.fichaColocada && this.fichaLista && !this.fichaDisparada){
                        var x2 = location.x;
                        var y2 = location.y;
                        this.wsEnviarDisparo(x2,y2);
                    }
                }
            }
        }
    },

    //Funciones para enviar cosas por el websocket

    wsEnviarFichaQuieta:function(){
        this.miWebSocket.doSend(MENSAJES.FICHAQUIETA+';'+this.miTurno);
    },
    wsEnviarSincroPosFicha:function(){
        var mensaje= MENSAJES.SINCROPOSFICHA;
        if (this.turno == this.miTurno){
            cc.log("mando POSICIONES");
            for (var i=1;i<=this.miTurno;i++){
                var j = this.jugadores.getJugador(i);
                var ficha = j.getFicha(i);
                var posx = ficha.GetPosition().x;
                var posy = ficha.GetPosition().y;
                var velx = ficha.GetLinearVelocity().x;
                var vely = ficha.GetLinearVelocity().y;
                mensaje = mensaje + ";" + posx + ";" + posy + ";" + velx+  ";" + vely;
            }
            this.miWebSocket.doSend(mensaje);
        }
    },
    wsRecibirSincroPosFicha:function(m){
        var b2Vec2 = Box2D.Common.Math.b2Vec2;
            cc.log("ACTUALIZO POSICIONES FICHAS");
            for (var i=1;i<m.length -1;i=i+4){
                var pos = Math.floor((i / 4)+1);
                var j = this.jugadores.getJugador(pos);
                var ficha = j.getFicha();
                var px = m[i];
                var py = m[i+1];
                var velx = m[i+2];
                var vely = m[i+3];
                cc.log("px: " + px + " py:" + py + " velx:" + velx + " vely:" + vely);
                //ficha.SetPosition(new b2Vec2(px, py));
                ficha.SetLinearVelocity(new b2Vec2(velx, vely));
            }
    },
    wsEnviarNombreJugador:function(nomj){
        this.miWebSocket.doSend(MENSAJES.ENVIARNOMBRE+';'+nomj);
        this.miNombre = nomj;
    },
    wsEnviarMostrarDisparador:function(x,y){
        this.miWebSocket.doSend(MENSAJES.MOSTRARDISPARADOR+';'+x+';'+y);
    },
    wsEnviarMostrarFicha:function(){
        this.miWebSocket.doSend(MENSAJES.MOSTRARFICHA+';ALDOPE');
    },
    wsEnviarActualizacionPosicionDisparador:function(x,y){
        this.miWebSocket.doSend(MENSAJES.ACTUALIZARPOSICIONDISPARADOR+';'+x+';'+y);
    },
    wsEnviarActualizacionPosicionFicha:function(x,y){
        this.miWebSocket.doSend(MENSAJES.ACTUALIZARPOSICIONFICHA+';'+x+';'+y);
    },
    wsEnviarDisparo:function(x2,y2){
        this.miWebSocket.doSend(MENSAJES.RECIBIRDISPARO+';'+x2+';'+y2);
    },
    wsEnviarColocada:function(x,y){
        this.miWebSocket.doSend(MENSAJES.RECIBIRCOLOCADA+';'+x+';'+y);
    },

    //Funciones para llamar al recibir mensajes por el websocket


    wsRecibirMeToca:function(val){
        cc.log("RECIBI meToca=" + val);
        this.meToca = val;
    },
    wsRecibirNombres:function(nombre,turno,metoca){
        var j = this.jugadores.getJugador(turno);
        j.setNombre(nombre);
        if (this.miNombre == nombre){
            this.miTurno = turno;
            this.wsRecibirMeToca(metoca);
        }
        if (turno==4)
            this.inicializar();
    },
    wsRecibirMostrarDisparador:function(x,y){
        this.disparador.setDibujar(true);
        //Si esta colocada y lista para disparar
        this.disparador.setv1(cc.p(x,y));
        this.disparador.setDibujar(true);
    },
    wsRecibirMostrarFicha:function(){
        this.fichaColocada = true;
        var batch = this.getChildByTag(TAG_SPRITE_MANAGER);
        batch.addChild(this.jugadores.getJugador(this.turno).getImagen());
    },
    wsRecibirActualizacionPosicionDisparador:function(x,y){
        this.disparador.setv2(cc.p(x,y));
    },
    wsRecibirActualizacionPosicionFicha:function(x,y){
        this.jugadores.getJugador(this.turno).getImagen().setPosition(cc.p(x,y));
    },
    wsRecibirDisparo:function(x2,y2){
        var x1 = this.disparador.getv1().x;
        var y1=  this.disparador.getv1().y;
        var fx = x1 - x2;
        var fy = y1 - y2;
        this.disparador.setv2(cc.p(x2,y2));
        cc.AudioEngine.getInstance().playEffect("Res/tirada");
        this.realizarTiro(this.turno,fx,fy);    //hacemos el tiro!

        this.fichaDisparada = true;             //indicamos que la ficha ya fue disparada

        this.fichaDisparada = false;
        this.fichaColocada = false;
        this.fichaLista = false;

        this.disparador.setDibujar(false);      //ya no dibujaremos el lanzador
        //this.turno = this.turno + 1;            //pasamos al siguiente turno

    },
    wsRecibirColocada:function(x,y){
        this.fichaLista = true;                     //La ficha ya fue posicionada en la mesa
        this.agregarFicha(x,y);
    }

});

MesaScene = MainScene.extend({
    runThisTest:function () {
        var layer = new MesaLayer();
        this.addChild(layer);

        cc.Director.getInstance().replaceScene(this);
    }
});